#include "ubvm_torus.h"
#include "DIVA_Manager.h"
#include <sstream>
#include "xParameterPack.h"
#include "vmLibrary.h"
#include "EntityMaterialInstance.h"
// 
//
//
const int NSIDES = 30 ;
const int NRINGS = 60 ;
int ubvm_torus::_UNIQUE_INT = 0 ;
void doughnut(float r, float R, int nsides, int rings, Ogre::ManualObject* manual);
ubvm_torus::ubvm_torus(xParameterPack xpp):DIVA_VM(xpp){

	int radius_port = vmLibrary::instance().get_vm_default_input_parameters().size();
	_vm_center_radius = xpp.paras[radius_port].val_int_ptr ; // set up the private attributes
	_vm_ring_radius = xpp.paras[radius_port+1].val_int_ptr ;

	init_default_parameters();
}
/// destructor
ubvm_torus::~ubvm_torus(){
}

void ubvm_torus::load_3Dresources() {

	const int COLOR_MODULATE_PARAM_INDEX = 1 ;
	_mgr = DIVA_Manager::getInstance()->getSceneManager();
	
	// we need to give a unique name, otherwise, when two torus are added to the scene
	// runtime error happens
	_manual_name = "torus"+Ogre::StringConverter::toString(_UNIQUE_INT) ;
	_manual = _mgr->createManualObject(_manual_name); 

	_manual->begin("TextureModColor", Ogre::RenderOperation::OT_TRIANGLE_LIST);
		doughnut((*_vm_ring_radius),(*_vm_center_radius),NSIDES, NRINGS, _manual); // 4 sides and  8 rings
    _manual->end();

	// convert it to mesh, because we want to change the color 
	_meshptr = _manual->convertToMesh("donut"+_UNIQUE_INT);
	_mesh_name = "donut"+_UNIQUE_INT ;
	_UNIQUE_INT++ ;

	_ent = _mgr->createEntity(getNewUniqueName(), _meshptr->getName());
	_SceneNode->attachObject(_ent);
}
void ubvm_torus::set_default_values() {

	_vm_rx_val = 0 ;
	_vm_ry_val = 0 ;
	_vm_rz_val = 0 ;

	Ogre::Vector3 sz = _ent->getBoundingBox().getSize();
	_vm_init_sizex = sz.x ;
	_vm_init_sizey = sz.y ;
	_vm_init_sizez = sz.z ;

	_vm_sizex_val = sz.x ;
	_vm_sizey_val = sz.y ;
	_vm_sizez_val = sz.z ;

	_vm_sizexscale_val = 1.0 ;
	_vm_sizeyscale_val = 1.0 ;
	_vm_sizezscale_val = 1.0 ;

	_vm_r_val = 0.2;
	_vm_g_val = 0.2;
	_vm_b_val = 0.2;
	_vm_transparency_val = 1.0 ;

	_vm_yaw_val = 0 ;
	_vm_pitch_val = 0 ;
	_vm_roll_val = 0 ;

}
void ubvm_torus::reg_event_entity() {
	
	// register the relation of the entity and vm in diva manager
	// When this entity is clicked, mouse/keyboard VM will be passed to this VM
	// By default it can be only one entity representing this VM
	VL_regBoundingBox(_ent);

}
void ubvm_torus::init_private_attrs_started() {
	
}
void ubvm_torus::init_private_attrs_ended() {}

void ubvm_torus::VMValueUpdated() {
	int radius_port = vmLibrary::instance().get_vm_default_input_parameters().size();
	if (_para_onoff[radius_port] || _para_onoff[radius_port+1] ) {

		DIVA_Manager::getInstance()->dereg_MovableObj_VM_relation(_ent,this); 
		// first, we should free the previous created resources
		_SceneNode->detachObject(_ent->getName());  // deattach 
		_mgr->destroyManualObject(_manual);
		_mgr->destroyEntity(_ent); 
		Ogre::MeshManager::getSingleton().remove(_mesh_name);

		// now, we create another new donut according to the updated values
		_manual = _mgr->createManualObject("torus"+_UNIQUE_INT);
		_manual->begin("TextureModColor", Ogre::RenderOperation::OT_TRIANGLE_LIST);
			doughnut((*_vm_ring_radius),(*_vm_center_radius),NSIDES, NRINGS, _manual); // 4 sides and  8 rings
		_manual->end();
		// convert it to mesh, because we want to change the color 
		_meshptr = _manual->convertToMesh("donut"+_UNIQUE_INT);
		_mesh_name = "donut"+_UNIQUE_INT ;
		_UNIQUE_INT++ ;
		_ent = _mgr->createEntity(getNewUniqueName(), _meshptr->getName());
		_SceneNode->attachObject(_ent);
		DIVA_Manager::getInstance()->reg_MovableObj_VM_relation(_ent,this); // register the new entity and vm relation
		                                                                    // if this step is not done, the dragging will
																			// not working
	}
	DIVA_VM::VMValueUpdated();
}

void ubvm_torus::setBodyScale(Ogre::Vector3 scale) {
	_SceneNode ->setScale(scale);
}
bool ubvm_torus::isBodyScaleWrtSceneNode() { return true ; }

Ogre::Vector3 ubvm_torus::getOriginalBodySize() {
	Ogre::AxisAlignedBox temp = _ent ->getBoundingBox();	
	Ogre::Vector3 size = temp.getSize(); 
	return size ;
}

Ogre::Vector3 ubvm_torus::getActualSize() {
	return getOriginalBodySize() * _SceneNode->getScale();
}
Ogre::Vector3 ubvm_torus::getBodyScale() {
	return _SceneNode->getScale();
}

void doughnut(float r, float R, int nsides, int rings, Ogre::ManualObject *manual)
{
  int i, j;
  const float M_PI = 3.14159 ;
  float theta, phi, theta1, phi1;
  float p0[03], p1[3], p2[3], p3[3];
  float n0[3], n1[3], n2[3], n3[3];
  int index ;

  index = 0 ;
  for (i = 0; i < rings ; i++) { //rings
	theta = (float) i *2.0 * M_PI / rings;
    theta1 = (float) (i + 1) * 2.0 * M_PI / rings;
    for (j = 0; j < nsides ; j++) { //sides
      phi = (float) j *2.0 * M_PI / nsides;
      phi1 = (float) (j + 1) * 2.0 * M_PI / nsides;

      p0[0] = cos(theta) * (R + r * cos(phi));
      p0[1] = -sin(theta) * (R + r * cos(phi));
      p0[2] = r * sin(phi);

      p1[0] = cos(theta1) * (R + r * cos(phi));
      p1[1] = -sin(theta1) * (R + r * cos(phi));
      p1[2] = r * sin(phi);

      p2[0] = cos(theta1) * (R + r * cos(phi1));
      p2[1] = -sin(theta1) * (R + r * cos(phi1));
      p2[2] = r * sin(phi1);

      p3[0] = cos(theta) * (R + r * cos(phi1));
      p3[1] = -sin(theta) * (R + r * cos(phi1));
      p3[2] = r * sin(phi1);

      n0[0] = cos(theta) * (cos(phi));
      n0[1] = -sin(theta) * (cos(phi));
      n0[2] = sin(phi);

      n1[0] = cos(theta1) * (cos(phi));
      n1[1] = -sin(theta1) * (cos(phi));
      n1[2] = sin(phi);

      n2[0] = cos(theta1) * (cos(phi1));
      n2[1] = -sin(theta1) * (cos(phi1));
      n2[2] = sin(phi1);

      n3[0] = cos(theta) * (cos(phi1));
      n3[1] = -sin(theta) * (cos(phi1));
      n3[2] = sin(phi1);

	
	  manual->position(Ogre::Vector3(p0[0],p0[1],p0[2])); 
	  manual->position(Ogre::Vector3(p2[0],p2[1],p2[2]));
	  manual->position(Ogre::Vector3(p1[0],p1[1],p1[2]));
	  manual->index(index);
	  manual->index(index+1);
	  manual->index(index+2);
	  index += 3 ;

	  manual->position(Ogre::Vector3(p0[0],p0[1],p0[2]));  
	  manual->position(Ogre::Vector3(p3[0],p3[1],p3[2])); 
	  manual->position(Ogre::Vector3(p2[0],p2[1],p2[2]));
	  manual->index(index);
	  manual->index(index+1);
	  manual->index(index+2);
	  index += 3 ;
 
    }
  }
}